#pragma once
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<cstring>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string>
#include<unistd.h>
#include<sys/wait.h>
#include<pthread.h>
#include<signal.h>
#include"log.hpp"
#include"ThreadPool.hpp"
#include"Task.hpp"
#include"Daemon.hpp"
extern Log lg;
const int defaultfd = -1;
const std::string defaultip = "0.0.0.0";
const uint16_t defaultport = 8080;
const int backlog = 7;

enum{
    SocketError = 1,
    BindError,
    ListenError
};

class TcpServer;

class ThreadData
{
public:
    ThreadData(int fd, const std::string &ip, const uint16_t &port, TcpServer* ts)
    :sockfd(fd), clientip(ip), clientport(port), ts(ts)
    {}
public:
    int sockfd;
    std::string clientip;
    uint16_t clientport;
    TcpServer* ts;
};

class TcpServer
{
public:
    TcpServer(const uint16_t& port = defaultport, const std::string& ip = defaultip):listensockfd_(defaultfd), port_(port), ip_(ip)
    {}
    void InitServer()
    {
        listensockfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if(listensockfd_ < 0)
        {
            lg(Fatal,"socket error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(SocketError);
        }
        lg(Info, " socket success listensockfd_: %d", listensockfd_);
        int opt = 1;
        setsockopt(listensockfd_, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
        struct sockaddr_in local;
        memset(&local,0,sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        local.sin_addr.s_addr = inet_addr(ip_.c_str());
        //inet_aton(ip_.c_str(), &(local.sin_addr));

        if(bind(listensockfd_, (struct sockaddr*)&local,sizeof(local)) < 0)
        {
            lg(Fatal, "bind error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(BindError);
        }
        lg(Info, "bind soccess");
        if(listen(listensockfd_, backlog) < 0)
        {
            lg(Fatal, "listen error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(ListenError);
        }
        lg(Info, "listen soccess");
    }
    // static void* Routine(void* args)
    // {
    //     pthread_detach(pthread_self());
    //     ThreadData* td = static_cast<ThreadData*>(args);
    //     td->ts->Service(td->sockfd, td->clientip, td->clientport);
    //     delete td;
    //     return nullptr;
    // }
    void Start()
    {
        lg.Enable(Classfile);
        Daemon();
        //signal(SIGPIPE, SIG_IGN);//防止写入时客户端关闭使进程退出
        ThreadPool<Task>::GetInstance()->Start();
        while(true)
        {
            lg(Info, "tcpserver is running...");
            while(true)
            {
                struct sockaddr_in client;
                socklen_t len = sizeof(client);
                int sockfd = accept(listensockfd_, (struct sockaddr*)&client, &len);
                if(sockfd < 0)
                {
                    lg(Warning, "accept Warning, errno: %d, errstring: %s", errno, strerror(errno));
                    continue;
                }
                uint16_t clientport = ntohs(client.sin_port);
                char clientip[32];
                inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));
                lg(Info, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, clientip, clientport);
                //Service(sockfd, clientip, clientport);
                //close(sockfd);
                //多进程
                // pid_t id = fork();
                // if(id == 0)
                // {
                //     close(listensockfd_);
                //     if(fork() > 0) exit(0);
                //     Service(sockfd, clientip, clientport);//孙子进程，system领养
                //     close(sockfd);
                //     exit(0);
                // }
                // close(sockfd);
                // pid_t rid = waitpid(id, nullptr, 0);
                // (void)rid;
                //多线程
                // ThreadData* td = new ThreadData(sockfd, clientip, clientport, this);
                // pthread_t pid;
                // pthread_create(&pid, nullptr, Routine, td);
                //线程池
                ThreadPool<Task>::GetInstance()->Push(Task(sockfd, clientip, clientport));
            }

        }
    }
    
    // void Service(int sockfd, const std::string& clientip, const uint16_t& clientport)
    // {
    //     char buffer[4096];
    //     while(true)
    //     {
    //         ssize_t n = read(sockfd, buffer, sizeof(buffer));
    //         if(n > 0)
    //         {
    //             buffer[n] = 0;
    //             std::cout << "client say# " << buffer << std::endl;
    //             std::string echo_string = "tcpserver echo# ";
    //             echo_string += buffer;
    //             write(sockfd, echo_string.c_str(), echo_string.size());
    //         }
    //         else if(n == 0)
    //         {
    //             lg(Info, "%s:%d quit, server close sockfd: %d", clientip.c_str(), clientport, sockfd);
    //             break;
    //         }
    //         else
    //         {
    //             lg(Warning, "read error, sockfd: %d,client ip: %s, client port: %d", sockfd, clientip.c_str(), clientport);
    //             break;
    //         }
    //     }
    // }
    ~TcpServer()
    {}
private:
    int listensockfd_;
    uint16_t port_;
    std::string ip_;
    

};